#include<iostream>

using namespace std ;

const int maxn = 100010 ;

//是堆的大小 ， m 表示输出前 m 个数
int n , m ;

//size 表示堆的大小
int heap[maxn] , size1 ;

//对下标为u的点进行down操作
void down(int u) {
    //这里面heap[i]存的是堆中排第 i 的那个结点的值
    int t = u ;
    if(u*2 <= size1 && heap[u*2] < heap[t]) {
        t = 2 * u;
    }
    if(u * 2 + 1 <= size1 && heap[u*2+1] < heap[t]) {
        t = u*2 + 1;
    }

    if(u != t) {
        swap(heap[t] , heap[u]) ;
        down(t);
    }
}

//up操作
void up(int u) {
    while(u / 2 && heap[u / 2] > heap[u]){
        swap(heap[u / 2] , heap[u]);
        u / = 2 ;
    }
}

int main() {

    scanf("%d%d" , &n , &m);

    //输入堆的元素
    for (int i = 1; i <= n; ++i) {
        scanf("%d" , &heap[i]);
    }
    size1 = n ;

    //堆调整，建立堆
    for (int i = n / 2; i ; --i) {
        down(i);
    }

    //堆排序
    while(m--){
        printf("%d " , heap[1]) ;
        heap[1] = heap[size1] ;
        size1--;
        down(1);
    }

    return 0 ;
}